library ieee;
use ieee.std_logic_1164.all;

entity mips is
-- TODO: Las variables de control, van como señales internas de mips o son I/O ?
    port (  dump, rst, clk : in std_logic;
--			AluControl	: in std_logic_vector(2 downto 0);
        	pc, instr	: out std_logic_vector(31 downto 0));
end entity;

architecture mips_arch of mips is

	component fetch 
		port (	Jump, PCSrcM, clk, rst: in std_logic;
				PcBranchM: in std_logic_vector(31 downto 0);
		    	InstrF, PCF, PCPlus4F: out std_logic_vector(31 downto 0));
	end component;

	component decode
		port(InstrD, Wd3: in std_logic_vector(31 downto 0);
			 A3: in std_logic_vector(4 downto 0);
			 clk, RegWrite: in std_logic;
			 SignImmD, RD1D, RD2D: out std_logic_vector(31 downto 0);
			 RtD, RdD: out std_logic_vector(4 downto 0));
	end component;

	component execute
		port ( RD1E, RD2E, PCPlus4E, SignImmE : in std_logic_vector (31 downto 0);
			   RtE, RdE : in std_logic_vector (4 downto 0);
			   RegDst, AluSrc: in std_logic;
			   AluControl : in std_logic_vector(2 downto 0);
			   AluOutE, WriteDataE, PCBranchE : out std_logic_vector (31 downto 0);
			   WriteRegE : out std_logic_vector(4 downto 0);
			   ZeroE : out std_logic);
	end component;

	component memory
		port( AluOutM, WriteDataM : in std_logic_vector(31 downto 0);
			   ZeroM, MemWrite, BranchM, clk, dump : in std_logic;
			   ReadDataM : out std_logic_vector(31 downto 0);
			   PCSrcM : out std_logic);
	end component;

	component writeback 
		port(AluOutW, ReadDataW: in std_logic_vector(31 downto 0);
			 MemToReg: in std_logic;
			 ResultW: out std_logic_vector(31 downto 0));
	end component;
	
	component controller is
	port (	Funct, Op	: in std_logic_vector(5 downto 0);
        	AluControl	: out std_logic_vector(2 downto 0);
        	MemToReg, MemWrite, Branch, AluSrc, RegDst, RegWrite, Jump: out std_logic);
    end component;
    
    component flopr is
    generic(value : integer := 32);
    port (
            d   :   in std_logic_vector((value - 1) downto 0);
            q   :   out std_logic_vector((value - 1) downto 0);
            rst :   in  std_logic;
            clk :   in  std_logic
          );
    end component;
    
    component floprb is
    port (	d   :   in std_logic;
            q   :   out std_logic;
            rst :   in  std_logic;
            clk :   in  std_logic
          );
	end component;

	
	signal PCPlus4F, InstrF, PCF : std_logic_vector(31 downto 0);
	signal PCPlus4D, SignImmD, RD1D, RD2D, InstrD : std_logic_vector(31 downto 0);
	signal PCBranchE, PCPlus4E, ALUOutE, SignImmE, WriteDataE, ReadDataE, RD1E, RD2E : std_logic_vector(31 downto 0);
	signal PCBranchM, ALUOutM, WriteDataM, ReadDataM : std_logic_vector(31 downto 0);
	signal ResultW, AluOutW, ReadDataW : std_logic_vector(31 downto 0);
	
	signal WriteRegE, WriteRegM, WriteRegW, RtD, RdD, RtE, RdE : std_logic_vector(4 downto 0);
	signal MemToRegD, MemWriteD, BranchD, AluSrcD, RegDstD, RegWriteD, JumpD : std_logic;
	signal PCSrcE, ZeroE, MemToRegE, MemWriteE, BranchE, AluSrcE, RegDstE, RegWriteE, JumpE : std_logic;
	signal PCSrcM, ZeroM, MemToRegM, MemWriteM, BranchM, RegWriteM, JumpM : std_logic;
	signal RegWriteW, MemToRegW : std_logic;
	signal AluControlD, AluControlE : std_logic_vector(2 downto 0);
	
	begin
	    -- mapeamos cada parte...
	    fetch_map : fetch port map (Jump => JumpM, PCSrcM => PCSrcM, clk => clk, rst => rst, PcBranchM => PCBranchM, InstrF => InstrF, PCF => PCF, PCPlus4F => PCPlus4F);
	    
		flopr_map1 : flopr port map (d => PCPlus4F, rst => rst, clk => clk, q => PCPlus4D);
		
		flopr_map2 : flopr port map (d => InstrF, rst => rst, clk => clk, q => InstrD);
	    
	    --flopr_map3 y flopr_map4 no existen... in your face!!
	    
	    instr <= InstrF;
	    pc <= PCF;
	    
	    controller_map : controller port map (Funct => InstrF(5 downto 0), Op => InstrF(31 downto 26), AluControl => AluControlD, MemToReg => MemToRegD, MemWrite => MemWriteD, Branch => BranchD, AluSrc => AluSrcD, RegDst => RegDstD, RegWrite => RegWriteD, Jump => JumpD);
	    
	    flopr_map5 : floprb port map (d => JumpD, rst => rst, clk => clk, q => JumpE);
	    
	    flopr_map6 : flopr generic map(value => 3) port map (d => AluControlD, q => AluControlE, rst => rst, clk => clk);
	    
	    flopr_map7 : floprb port map (d => MemToRegD, rst => rst, clk => clk, q => MemToRegE);
	    
	    flopr_map8 : floprb port map (d => MemWriteD, rst => rst, clk => clk, q => MemWriteE);
	    
	    flopr_map9 : floprb port map (d => BranchD, rst => rst, clk => clk, q => BranchE);
	    
	    flopr_map10 : floprb port map (d => AluSrcD, rst => rst, clk => clk, q => AluSrcE);
	    
	    flopr_map11 : floprb port map (d => RegDstD, rst => rst, clk => clk, q => RegDstE);
	    
	    flopr_map12 : floprb port map (d => RegWriteD, rst => rst, clk => clk, q => RegWriteE);
	    
	    decode_map : decode port map (InstrD => InstrD, Wd3 => ResultW, A3 => WriteRegW(4 downto 0), clk => clk, RegWrite => RegWriteD, SignImmD => SignImmD, RD1D => RD1D, RD2D => RD2D, RtD => RtD, RdD => RdD);
	    
	    -- flopr_map13 no está por supersticiones estúpidas
	    
		flopr_map14 : flopr port map (d => RD1D, rst => rst, clk => clk, q => RD1E);
		
		flopr_map15 : flopr port map (d => RD2D, rst => rst, clk => clk, q => RD2E);
		
		flopr_map16 : flopr generic map(value => 5) port map (d => RtD, rst => rst, clk => clk, q => RtE);
		
		flopr_map17 : flopr generic map(value => 5) port map (d => RdD, rst => rst, clk => clk, q => RdE);
		
		flopr_map18 : flopr port map (d => SignImmD, rst => rst, clk => clk, q => SignImmE);
	    
	    execute_map : execute port map (RD1E => RD1E, RD2E => RD2E, PCPlus4E => PCPlus4E, SignImmE => SignImmE, RtE => Rte, RdE => RdE, RegDst => RegDstE, AluSrc => AluSrcE, AluControl => AluControlE, AluOutE => AluOutE, WriteDataE => WriteDataE, PCBranchE => PCBranchE, WriteRegE => WriteRegE, ZeroE => ZeroE);
	    
	    flopr_map19 : floprb port map (d => JumpE, rst => rst, clk => clk, q => JumpM);
	    
	    flopr_map20 : floprb port map (d => MemToRegE, rst => rst, clk => clk, q => MemToRegM);
	    
	    flopr_map21 : floprb port map (d => MemWriteE, rst => rst, clk => clk, q => MemWriteM);
	    
	    flopr_map22 : floprb port map (d => BranchE, rst => rst, clk => clk, q => BranchM);
	    
	    flopr_map23 : floprb port map (d => RegWriteE, rst => rst, clk => clk, q => RegWriteM);
	    
	    flopr_map24 : floprb port map (d => ZeroE, rst => rst, clk => clk, q => ZeroM);
	    
	    flopr_map25 : flopr port map (d => ALUOutE, rst => rst, clk => clk, q => ALUOutM);
	    
	    flopr_map26 : flopr port map (d => WriteDataE, rst => rst, clk => clk, q => WriteDataM);
	    
	    flopr_map27 : flopr generic map(value => 5) port map (d => WriteRegE, rst => rst, clk => clk, q => WriteRegM);
	    
	    memory_map : memory port map (AluOutM => AluOutM, WriteDataM => WriteDataM, ZeroM => ZeroM, MemWrite => MemWriteM, BranchM => BranchM, clk => clk, dump => dump, ReadDataM => ReadDataM, PCSrcM => PCSrcM);
	    
	    flopr_map28 : floprb port map (d => RegWriteM, rst => rst, clk => clk, q => RegWriteW);
	    
	    flopr_map29 : floprb port map (d => MemToRegM, rst => rst, clk => clk, q => MemToRegW);
	    
	    flopr_map30 : flopr port map (d => ALUOutM, rst => rst, clk => clk, q => ALUOutW);
	    
	    flopr_map31 : flopr port map (d => ReadDataM, rst => rst, clk => clk, q => ReadDataW);
	    
	    flopr_map32 : flopr generic map(value => 5) port map (d => WriteRegM, rst => rst, clk => clk, q => WriteRegW);
	    
	    writeback_map : writeback port map (AluOutW => AluOutW, ReadDataW => ReadDataW, MemToReg => MemToRegW, ResultW => ResultW);
	    
	    flopr_final : flopr port map (d => InstrF, q => instr, rst => '0', clk => clk);

end architecture;
